/*
 * @Description: 添加字段显隐规则-第二个Drawer
 * @Autor: gufuyan
 * @Date: 2021-11-15 11:26:31
 * @lastModifiedBy: gufuyan
 * @LastEditTime: 2021-12-03 15:28:05
 * @lastModifiedContent:
 */

import React, { useState, useEffect } from 'react';
import { Tree, Drawer, Button, Input, message } from 'antd';
import { useModel } from 'umi';
import { intl } from '../FormAttributes';
import type { IAddValidationRuleProps, FnItemT, VarTree, VarList } from './data';
import { fnDataTree, fnDataList, componentTip, defaultDesc } from './constants';
import { UnControlled as CodeMirror } from 'react-codemirror2';
import 'codemirror/addon/hint/javascript-hint.js';
import 'codemirror/addon/hint/show-hint.js';
import 'codemirror/addon/hint/show-hint.css';
import 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
import 'codemirror/mode/javascript/javascript.js';
import './codemirror.less';
import styles from './index.less';

const { Search } = Input;

const AddFieldRule: React.FC<IAddValidationRuleProps> = (props) => {
  // 可用变量
  const [varTree, setVarTree] = useState<VarTree[]>([]);
  const [varList, setVarList] = useState<VarList[]>([]);
  const [varExpandedKeys, setVarExpandedKeys] = useState<React.Key[]>([]);
  const [varSearchValue, setVarSearchValue] = useState<string>('');
  const [varAutoExpandParent, setVarAutoExpandParent] = useState<boolean>(true);
  const [selectField, setSelectField] = useState<VarList[]>([]);
  // 函数
  const [fnTree] = useState(fnDataTree);
  const [fnList] = useState(fnDataList);
  const [fnExpandedKeys, setFnExpandedKeys] = useState<React.Key[]>([]);
  const [fnSearchValue, setFnSearchValue] = useState<string>('');
  const [fnAutoExpandParent, setFnAutoExpandParent] = useState<boolean>(true);
  // 选中的公式描述
  const [fnSelectItem, setFnSelectItem] = useState<FnItemT>(defaultDesc);
  // 配置全局信息
  const drag = useModel('drag');
  // codemirror对象
  const [instance, setInstance] = useState<any>(null);
  // 错误说明文字
  const [errorText, setErrorText] = useState<string>();

  useEffect(() => {
    // 初始化根据layoutData赋值可用变量的tree和list
    const tree: React.SetStateAction<VarTree[]> = [];
    const list: React.SetStateAction<VarList[]> = [];
    drag.config?.contentItem?.forEach(
      (el: { id: string; title: string; name: string; field: string; children: any }) => {
        const data: any = {
          key: el.id,
          title: el.title,
          type: el.name,
          fieldName: el.field,
        };
        list.push({ ...data });
        if (el.children && el.children.length) {
          data.children = [];
          el.children[0].forEach(
            (childEl: { id: string; title: string; name: string; field: string }) => {
              const cData = {
                key: childEl.id,
                title: childEl.title,
                type: childEl.name,
                fieldName: childEl.field,
              };
              data.children.push(cData);
              list.push(cData);
            },
          );
        }
        tree.push(data);
      },
    );
    setVarTree(tree);
    setVarList(list);
  }, [drag]);

  useEffect(() => {
    // 新增公式
    if (!props.visible) return;
    if (props.editType === 'add') {
      setErrorText('');
      if (instance) instance.doc.setValue('');
      return;
    }
    // 编辑公式，处理赋值逻辑
    const data = props.editRule;
    setErrorText(data.remind);
    if (instance) {
      instance.doc.setValue(data.formula);
      const formulaArr = data.formula.split('');
      const fieldArr: { beginCh: number; endCh: number }[] = [];
      let [bCount, eCount, beginCh, endCh] = [0, 0, 0, 0];
      formulaArr.forEach((el: string, index: number) => {
        if (el === '$') {
          bCount++;
          beginCh = index;
        }
        if (el === '#') {
          eCount++;
          endCh = index;
        }
        if (bCount === eCount && fieldArr.length != eCount) {
          fieldArr.push({
            beginCh,
            endCh,
          });
        }
      });
      fieldArr.forEach((item) => {
        instance.doc.markText(
          { line: 0, ch: item.beginCh },
          { line: 0, ch: item.endCh + 1 },
          {
            className: 'codemirror-field-show',
            atomic: true,
            selectLeft: true,
            selectRight: true,
          },
        );
      });
    }
  }, [props.editRule, props.editType, props.visible]);

  /**
   * 获取父级ID
   * @param key
   * @param tree
   * @returns keys
   */
  const getParentKey: (key: string, tree: any) => string[] = (key, tree) => {
    let parentKey;
    for (let i = 0; i < tree.length; i++) {
      const node = tree[i];
      if (node.children) {
        if (node.children.some((item: { key: string }) => item.key === key)) {
          parentKey = node.key;
        } else if (getParentKey(key, node.children)) {
          parentKey = getParentKey(key, node.children);
        }
      }
    }
    return parentKey;
  };

  /**
   * 字段变量: 搜索
   * @param e
   */
  const onSearchVar = (e: { target: { value: string } }) => {
    const { value } = e.target;
    const expandedKeys: any = varList
      .map((item) => {
        if (item.title.indexOf(value) > -1) {
          return getParentKey(item.key, varTree);
        }
        return null;
      })
      .filter((item, i, self) => item && self.indexOf(item) === i);

    setVarExpandedKeys(expandedKeys);
    setVarSearchValue(value);
    setVarAutoExpandParent(true);
  };

  /**
   * 字段变量: 展开/收起节点更新值
   * @param expandedKeys
   */
  const onExpandVar = (expandedKeys: React.Key[]) => {
    setVarExpandedKeys(expandedKeys);
    setVarAutoExpandParent(false);
  };

  /**
   * 字段变量: 点击选择
   * @param keys
   */
  const onSelectVar = (keys: React.Key[]) => {
    if (!keys.length) return;
    const item: any = varList.filter((el) => el.key === keys[0]);
    const newselectField = selectField;
    newselectField.push(item[0]);
    setSelectField(newselectField);

    // 待整理
    const title = `[${item[0].title}]`;
    const key = `\$${item[0].key}#`;
    const cursor = instance.doc.getCursor();
    instance.doc.replaceRange(
      // `${title}${key}`,
      `${key}`,
      { line: cursor.line, ch: cursor.ch },
      { line: cursor.line, ch: cursor.ch },
      // '*',
    );

    // instance.doc.replaceSelection(`${title}${key}`, 'around');
    // instance.doc.replaceSelection(`${title}`, 'around');

    instance.doc.markText(
      { line: cursor.line, ch: cursor.ch },
      { line: cursor.line, ch: cursor.ch + key.length },
      {
        className: 'codemirror-field-show',
        atomic: true,
        selectLeft: true,
        selectRight: true,
        startStyle: 'startStyle',
        endStyle: 'endStyle',
        attributes: {
          'data-field': title,
        },
      },
    );

    // instance.doc.markText(
    //   { line: cursor.line, ch: cursor.ch },
    //   { line: cursor.line, ch: cursor.ch + title.length + key.length },
    //   {
    //     className: 'codemirror-field-show',
    //     atomic: true,
    //     selectLeft: true,
    //     selectRight: true,
    //     startStyle: 'startStyle',
    //     endStyle: 'endStyle',
    //     attributes: {
    //       'data-field': title,
    //     },
    //   },
    // );

    // instance.doc.markText(
    //   { line: cursor.line, ch: cursor.ch + title.length },
    //   { line: cursor.line, ch: cursor.ch + title.length + key.length },
    //   {
    //     className: 'codemirror-field-hide',
    //   },
    // );

    // instance.execCommand('goGroupRight')
  };

  /**
   * 字段变量: 遍历
   * @param data
   * @returns JSX
   */
  const loopVar = (data: any) =>
    data.map((item: any) => {
      const index = item.title.indexOf(varSearchValue);
      const beforeStr = item.title.substr(0, index);
      const afterStr = item.title.substr(index + varSearchValue.length);
      const title =
        index > -1 ? (
          <div className={styles.varItem}>
            <span className={styles.text}>
              {beforeStr}
              <span className="site-tree-search-value">{varSearchValue}</span>
              {afterStr}
            </span>
            <label className={styles.tab}>{componentTip[item.type]}</label>
          </div>
        ) : (
          <div className={styles.varItem}>
            <span className={styles.text}> {item.title} </span>
            <label className={styles.tab}>{componentTip[item.type]}</label>
          </div>
        );
      if (item.children) {
        return { title, key: item.key, children: loopVar(item.children) };
      }

      return {
        title,
        key: item.key,
      };
    });

  /**
   * 函数: 搜索
   * @param e
   */
  const onChangeFn = (e: { target: { value: string } }) => {
    const { value } = e.target;
    const expandedKeys: any = fnList
      .map((item) => {
        if (item.title.indexOf(value) > -1) {
          return getParentKey(item.key, fnTree);
        }
        return null;
      })
      .filter((item, i, self) => item && self.indexOf(item) === i);

    setFnExpandedKeys(expandedKeys);
    setFnSearchValue(value);
    setFnAutoExpandParent(true);
  };

  /**
   * 函数: 展开/收起节点更新值
   * @param expandedKeys
   */
  const onExpandFn = (expandedKeys: React.Key[]) => {
    setFnExpandedKeys(expandedKeys);
    setFnAutoExpandParent(false);
  };

  /**
   * 函数: 点击选择
   * @param keys
   */
  const onSelectFn = (keys: React.Key[]) => {
    if (keys[0] && ('' + keys[0]).includes('-')) {
      const item: any = fnList.filter((el) => el.key === keys[0]);
      setFnSelectItem(item[0]);
      const cursor = instance.doc.getCursor();
      instance.doc.replaceRange(
        `${item[0].title}()`,
        { line: cursor.line, ch: cursor.ch },
        { line: cursor.line, ch: cursor.ch },
      );
    }
  };

  /**
   * 函数: 遍历
   * @param data
   * @returns
   */
  const loopFn = (data: any) =>
    data.map((item: any) => {
      const index = item.title.indexOf(fnSearchValue);
      const beforeStr = item.title.substr(0, index);
      const afterStr = item.title.substr(index + fnSearchValue.length);
      const title =
        index > -1 ? (
          <span>
            {beforeStr}
            <span className="site-tree-search-value">{fnSearchValue}</span>
            {afterStr}
          </span>
        ) : (
          <span>{item.title}</span>
        );
      if (item.children) {
        return { title, key: item.key, children: loopFn(item.children) };
      }

      return {
        title,
        key: item.key,
      };
    });

  /**
   * 提示补全功能
   * @param cmInstance
   * @returns
   */
  const handleShowHint = (cmInstance: any) => {
    const cursor = cmInstance.getCursor();
    const token = cmInstance.getTokenAt(cursor);
    const length = token.string.length;
    let childrens: any[] = [];
    fnDataTree.map((item) => {
      childrens = childrens.concat(item.children);
    });
    const hintList = childrens
      .filter((item) => {
        return item.title.substring(0, length) === token.string.toUpperCase();
      })
      .map((item) => ({
        text: `${item.title}()`,
        displayText: item.title,
      }));
    return {
      list: hintList,
      from: {
        ch: token.start,
        line: cursor.line,
      },
      to: {
        ch: token.end,
        line: cursor.line,
      },
    };
  };

  /**
   * 添加校驗提交
   */
  const onSubmit = () => {
    const value = instance.doc.getValue();
    if (props.type === 'form' && !errorText?.length) {
      message.error('请输入不满足校验条件时提示文字，在提交！');
      return;
    }

    if (!value?.length) {
      message.error('请配置公式，在提交！');
      return;
    }
    props.onClose({
      formula: value,
      remind: errorText,
      tempId: new Date().getTime(),
    });
  };

  return (
    <Drawer
      title={
        props.type === 'component' ? intl('drag.validate.title3') : intl('drag.validate.title2')
      }
      key="childDrawer"
      placement="left"
      width={1000}
      closable={false}
      onClose={() => props.onClose}
      visible={props.visible}
      className={styles.validateBox}
      footer={
        <div className={styles.footer}>
          <Button className={styles.btn} onClick={() => props.onClose()}>
            {intl('drag.cancel')}
          </Button>
          <Button className={styles.btn} type="primary" onClick={onSubmit}>
            {intl('drag.add')}
          </Button>
        </div>
      }
    >
      {/* 校验提示文字 */}
      {props.type === 'form' && (
        <div className={styles.error}>
          <div className={styles.label}>{intl('drag.validate.errorTip')}</div>
          <Input
            className={styles.input}
            value={errorText}
            onChange={(e) => setErrorText(e.target.value)}
          />
        </div>
      )}

      {/* 公式 */}
      <div className={styles.formula}>
        <div className={styles.text}>
          {props.type === 'component' ? `${props.field.title} =` : intl('drag.validate.formula')}
        </div>
        <CodeMirror
          editorDidMount={(editor) => {
            editor.setSize('100%', 120);
            setInstance(editor);
          }}
          value={''}
          options={{
            mode: 'javascript',
            lineNumbers: true,
            hintOptions: {
              completeSingle: false,
              hint: handleShowHint,
            },
          }}
          onCursorActivity={(cm: any) => {
            cm.showHint();
          }}
        />
      </div>

      <div className={styles.content}>
        {/* 可用变量 */}
        <div className={styles.varBox}>
          <div className={styles.titieBox}>{intl('drag.validate.var')}</div>
          <Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onSearchVar} />
          <div className={styles.treeContent}>
            <Tree
              onExpand={onExpandVar}
              expandedKeys={varExpandedKeys}
              autoExpandParent={varAutoExpandParent}
              treeData={loopVar(varTree)}
              onSelect={onSelectVar}
            />
          </div>
        </div>

        {/* 函数 */}
        <div className={styles.fnBox}>
          <div className={styles.titieBox}>{intl('drag.validate.fn')}</div>
          <Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onChangeFn} />
          <div className={styles.treeContent}>
            <Tree
              onExpand={onExpandFn}
              expandedKeys={fnExpandedKeys}
              autoExpandParent={fnAutoExpandParent}
              treeData={loopFn(fnTree)}
              onSelect={onSelectFn}
            />
          </div>
        </div>

        {/* 函数描述信息 */}
        <div className={styles.descBox}>
          <div className={styles.titieBox}>{fnSelectItem.title}</div>
          <code>{intl(fnSelectItem?.intro || '')}</code>
          <br />
          <code>{intl(fnSelectItem?.usage || '')}</code>
          <br />
          <code>{intl(fnSelectItem?.example || '')}</code>
        </div>
      </div>
    </Drawer>
  );
};

export default AddFieldRule;
